///
use crate::model::malines::ma::MAConfig;
use crate::model::malines::ma::PeriodV;
use crate::model::malines::ma::MA;
use crate::model::malines::smpr::SMPR;
use anyhow::anyhow;
use anyhow::Result;
use yata::core::Method;
use yata::helpers::Peekable;
use crate::round2;
/// 倍量计算，计算周期内某个值（如收盘价、成交量）最大值与均值比较的倍数，用于放量、涨幅倍数计算
#[derive(Debug)]
pub struct Smpr {
    /// smpr computer for each period
    smprs: Vec<(u8, SMPR)>,
}

impl Smpr {
    pub fn new(ma_config: &MAConfig, init_value: &f64) -> Result<Self> {
        let smprs: Vec<(u8, SMPR)> = ma_config.periods
            .iter()
            .map(|&period| Self::create_smpr(period, init_value))
            .collect::<Result<Vec<_>, _>>()?;
        Ok(Smpr { smprs: smprs })
    }

    pub fn next(&mut self, value: &f64) -> MA<f64> {
        Self::compute(&mut self.smprs, value)
    }

    pub fn repeat(&mut self, value: &f64) -> MA<f64> {
        let mut smprs = self.smprs.clone();
        Self::compute(&mut smprs, value)
    }

    fn compute(smprs: &mut Vec<(u8, SMPR)>, value: &f64) -> MA<f64> {
        for smpr in smprs.iter_mut() {
            smpr.1.next(value);
        }

        let mas: Vec<PeriodV<f64>> = smprs
            .iter()
            .map(|(period, smpr)| PeriodV {
                period: period.clone() as u16,
                value: round2(smpr.peek()),
            })
            .collect();

        let ma = MA { values: mas };
        return ma;
    }

    // Function to create an SMX instance and handle potential errors.
    pub fn create_smpr(period: u8, initial_value: &f64) -> Result<(u8, SMPR)> {
        let rs = SMPR::new(period, initial_value).map_err(|e|
            anyhow!("Failed to create SMX: {}", e)
        );
        match rs {
            Ok(rs) => Ok((period, rs)),
            Err(e) => Err(e),
        }
    }
}

#[cfg(test)]
mod test {
    use surrealdb::sql::Thing;

    use crate::db::malines::smpr::Smpr;
    use crate::model::kline::Kline;
    use crate::model::malines::ma::MAConfig;

    fn dummy_klines(size: u8) -> Vec<Kline> {
        let mut klines = Vec::new();
        for i in 0..size {
            let kl = Kline {
                id: Some(Thing::from(("kline", i.to_string().as_str()))),
                volume: (i as u64) + 1u64,
                ..Default::default()
            };
            klines.push(kl);
        }
        klines
    }

    #[tokio::test]
    async fn test_smpr_next() {
        let klines = dummy_klines(10);

        let mut smpr = Smpr::new(&MAConfig::default(), &(klines[0].volume as f64)).unwrap();

        for (idx, kl) in klines.iter().enumerate() {
            let value = smpr.next(&(kl.volume as f64));
            println!("smpr[{idx:02}]: volume={} => {:?}", kl.volume, value);
        }
    }

    #[tokio::test]
    async fn test_smpr_repeat() {
        let klines = dummy_klines(4);

        let mut smpr = Smpr::new(&MAConfig::default(), &(klines[0].volume as f64)).unwrap();

        for (idx, kl) in klines.iter().enumerate() {
            let value = smpr.next(&(kl.volume as f64));
            println!("smpr[{idx:02}]: volume={} => {:?}", kl.volume, value);
        }
        println!("\n\nnsmpr={:?}", smpr);

        let kl = Kline {
            id: Some(Thing::from(("kline", "5"))),
            volume: 5u64,
            ..Default::default()
        };
        for i in 0..3 {
            let value = smpr.repeat(&(kl.volume as f64));
            println!("\nsmpr[{i}]: volume={} => {:?}", kl.volume, value);
        }
        println!("\n\nsmpr={:?}", smpr);
    }
}
